/////////////////////////////////////////////////////////////////////////
// MIT License
//
// Copyright (c) 2000-2011 OpenNETCF Consulting, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
////////////////////////////////////////////////////////////////////////

using System;
using System.Reflection;
using System.Drawing;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;
using OpenNETCF.Windows.Forms;

namespace OpenNETCF.Windows.Forms.Calendar
{
    /// <summary>
    /// Agenda view control similar to the Windows Mobile calender application
    /// </summary>
    public class AgendaView: BaseCalendar
    {
        /// <summary>
        /// Occurs when an item is selected
        /// </summary>
        public event EventHandler ItemSelected;
        /// <summary>
        /// Occurs when item details are about to be drawn
        /// </summary>
        public event DrawItemDetailsDelegate DrawItemDetails;
        /// <summary>
        /// The selected item in the agenda view
        /// </summary>
        public CalendarItem SelectedItem
        {
            get
            {
                if (m_list == null)
                    return null;
                if (m_list.SelectedIndex < m_items.Length && m_list.SelectedIndex >= 0)
                    return m_items[m_list.SelectedIndex];
                return null;
            }
            set
            {
                for (int i = 0; i < m_items.Length; i++)
                    if (m_items[i] == value)
                        m_list.SelectedIndex = i;
            }
        }

        /// <summary>
        /// The items in the current agenda view
        /// </summary>
        public CalendarItem[] Items
        {
            get { return m_items; }
        }

        private AgendaList m_list;
        private Font m_fontBold;
        private Button2[] m_arrBtnWeek;
        private System.Windows.Forms.MonthCalendar m_cal;
        private Rectangle m_rDate;

        /// <summary>
        /// Creates any controls needed to be functional
        /// </summary>
        protected override void CreateControls()
        {
            base.CreateControls();

            m_list = new AgendaList();
            m_list.Font = new Font("Tahoma", 8, FontStyle.Regular);
            m_list.Bounds = new Rectangle(0, m_rTopBar.Bottom, Width, Height - m_rTopBar.Height);
            m_list.SelectedIndexChanged += new EventHandler(m_list_SelectedIndexChanged);
            m_list.DrawItem += new DrawItemEventHandler(m_list_DrawItem);
            m_list.Click += new EventHandler(m_list_Click);
            Controls.Add(m_list);
            
            m_btnYear.Visible = false;
            m_btnMonth.Visible = false;
            
            m_arrBtnWeek = new Button2[7];
            for (int i = 0; i < m_arrBtnWeek.Length; i++)
            {
                Button2 btn = new Button2();
                m_arrBtnWeek[i] = btn;
                btn.BackColor = BackColor;
                btn.ForeColor = this.ButtonForeColor(i);
                btn.BorderColor = BackColor;
                btn.Text = ((DayOfWeek)(i)).ToString().Substring(0, 1);
                btn.Font = new Font("Tahoma", 8, FontStyle.Bold);
                btn.Click += new EventHandler(WeekDay_Click);
                btn.ActiveForeColor = SystemColors.HighlightText;
                btn.ActiveBackColor = SystemColors.Highlight;
                Controls.Add(btn);
            }
            
            m_cal = new System.Windows.Forms.MonthCalendar();
            m_cal.Visible = false;
            m_cal.Font = Font;
            m_cal.DateChanged += new DateRangeEventHandler(MonthCal_DateChanged);
            
            Controls.Add(m_cal);
        }

        void m_list_Click(object sender, EventArgs e)
        {
             this.HideMonthCalendar();
        }

        void m_list_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (DrawItemDetails != null)
            {
                DrawItemDetails(e.Graphics, e.Bounds, Items[e.Index]);
            }
            else
            {
                Brush brDayFG;
                Rectangle rcClip = e.Bounds;
                rcClip.Inflate(1, 1);
                e.Graphics.Clip = new Region(rcClip);
                if ((e.State & DrawItemState.Selected) == DrawItemState.Selected && e.Index < Items.Length)
                {
                    e.Graphics.Clear(SystemColors.Highlight);
                    brDayFG = new SolidBrush(SystemColors.HighlightText);
                }
                else
                {
                    e.Graphics.DrawImage(m_list.BackgroundImage, e.Bounds, e.Bounds, GraphicsUnit.Pixel);
                    brDayFG = new SolidBrush(SystemColors.ControlText);
                }
                if ((e.State & DrawItemState.Focus) == DrawItemState.Focus)
                    e.DrawFocusRectangle();
                CalendarItem item = Items[e.Index];
                RectangleF rcf = new RectangleF(e.Bounds.Left + 2, e.Bounds.Top + 2, e.Bounds.Width, e.Bounds.Height / 2);
                e.Graphics.DrawString(item.Text, m_fontBold, brDayFG, rcf);
                string sRange = string.Format("{0}-{1}", item.StartTime.ToString("hh:mmt").ToLower(), item.EndTime.ToString("hh:mmt").ToLower());
                rcf = new RectangleF(rcf.Left, rcf.Bottom, rcf.Width, rcf.Height);
                e.Graphics.DrawString(sRange, Font, brDayFG, rcf);
                //e.Graphics.DrawLine(m_penGrid, e.Bounds.Left, e.Bounds.Top, e.Bounds.Right, e.Bounds.Top);
                e.Graphics.DrawLine(m_penGrid, e.Bounds.Left, e.Bounds.Bottom, e.Bounds.Right, e.Bounds.Bottom);
                brDayFG.Dispose();
                e.Graphics.ResetClip();
            }
        }

        /// <summary>
        /// Raises the OpenNETCF.Windows.Forms.Calendar.AgendaView.ItemSelected event
        /// </summary>
        protected void OnItemSelected()
        {
            if (ItemSelected != null)
                ItemSelected(this, new EventArgs());
        }

        void m_list_SelectedIndexChanged(object sender, EventArgs e)
        {
            OnItemSelected();
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.Resize event
        /// </summary>
        /// <param name="e"></param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            Graphics g = CreateGraphics();
            SizeF szText = g.MeasureString("W", m_arrBtnWeek[0].Font);

            m_rTopBar = new Rectangle(0, 0, Width, (int)(szText.Height * 2));

            m_list.Bounds = new Rectangle(0, m_rTopBar.Bottom, ClientRectangle.Width, ClientRectangle.Height - m_rTopBar.Height);
            //m_list.BackgroundImage = UIUtils.GenerateGradientBG(m_list.Width, m_list.Height, Color.FromArgb(200, 200, 255), Color.FromArgb(200, 200, 255), Color.FromArgb(188, 188, 255), Color.FromArgb(188, 188, 255));
            Image image = UIUtils.GetGradientBG(m_list.Width, m_list.Height, true);
#if EVAL_VERSION
            g = Graphics.FromImage(image);
            UIUtils.PaintWatermark(g, image.Width, image.Height);
#endif
            m_list.BackgroundImage = image;

            int btnWidth = (int)(szText.Width * 1.5);
            int btnHeight = (int)(szText.Height * 1.5);
            int btnPitch = btnWidth;// +1;
            Point ptBase = new Point((Width - 6 * btnPitch - btnWidth) / 2, (int)(m_rTopBar.Height - btnHeight) / 2);
            for (int i = 0; i < m_arrBtnWeek.Length; i++)
            {
                Button2 btn = m_arrBtnWeek[i];
                btn.Text = ((DayOfWeek)(i)).ToString().Substring(0, 1);
                btn.Bounds = new Rectangle(ptBase.X, ptBase.Y, btnWidth, btnHeight);
                ptBase.Offset(btnPitch, 0);
            }

            m_btnRight.Location = new Point(Width - m_btnRight.Width - 4, ptBase.Y);
            m_btnLeft.Location = new Point(m_btnRight.Left - m_btnLeft.Width - 3, m_btnRight.Top);
            m_btnToday.Location = new Point(m_btnLeft.Left - m_btnToday.Width - 3, m_btnRight.Top);

            szText = g.MeasureString("Www 00, 00", m_arrBtnWeek[0].Font);
            m_rDate = new Rectangle(2, (int)(m_rTopBar.Height - szText.Height) / 2, (int)(szText.Width * 1.2), (int)(szText.Height));
            m_cal.Top = m_rTopBar.Bottom;
            m_cal.Left = m_rDate.Left;

            g.Dispose();
            Recalculate();
            
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.FontChanged event
        /// </summary>
        protected override void OnFontChanged()
        {
            base.OnFontChanged();
            m_fontBold = new Font(Font.Name, Font.Size, FontStyle.Bold);
            if (m_arrBtnWeek != null)
            {
                foreach (Button2 btn in m_arrBtnWeek)
                {
                    btn.Font = m_fontBold;
                }
            }
            Recalculate();
        }

        /// <summary>
        /// Recalculates the control
        /// </summary>
        protected override void Recalculate()
        {
            base.Recalculate();
            if (Handle != IntPtr.Zero)
            {
                Graphics g = CreateGraphics();
                SizeF sz = g.MeasureString("hg", Font);
                if (m_list != null)
                    m_list.ItemHeight = (int)(sz.Height * 2 + 6);
            }
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.PaintBackground event
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.Paint event
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.Clear(BackColor);
          

            e.Graphics.DrawRectangle(m_penGrid, m_rTopBar);
            e.Graphics.DrawLine(m_penGrid, (m_btnLeft.Right + m_btnRight.Left) / 2, m_btnRight.Top, (m_btnLeft.Right + m_btnRight.Left) / 2, m_btnRight.Bottom);
            string sDate = Date.ToString("MMM dd, yy");
            e.Graphics.DrawString(sDate, m_fontBold, m_brDayFG, new RectangleF(m_rDate.Left, m_rDate.Top, m_rDate.Width, m_rDate.Height));

#if EVAL_VERSION
            UIUtils.PaintWatermark(e.Graphics, this.Width, this.Height); ;
#endif
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.MouseDown event
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (m_rDate.Contains(e.X, e.Y))
            {
                m_cal.BringToFront();
                m_cal.Visible = !m_cal.Visible;
                this.m_cal.SelectionStart = this.Date;
                if (m_cal.Visible)
                {
                    m_cal.Focus();
                    //m_cal.Capture = true;
                }
            }
            else
            {
                this.HideMonthCalendar();
            }

        }

        /// <summary>
        /// Raises the OpenNETCF.Windows.Forms.AgendaView.DateChanged event
        /// </summary>
        protected override void OnDateChanged()
        {
            m_list.SelectedIndexChanged -= new EventHandler(m_list_SelectedIndexChanged);
            this.m_list.SelectedIndex = -1;
            if (DataProvider != null)
            {
                CalendarItem today = new CalendarItem(Date.Date, Date.Date.AddHours(23.99));
                ArrayList items = new ArrayList();
                CalendarItem[] data = DataProvider.GetItemsForDateRange(Date, TimeSpan.FromDays(1));
                foreach (CalendarItem item in data)
                    if (item.Overlaps(today))
                        items.Add(item);
                m_items = (CalendarItem[])items.ToArray(typeof(CalendarItem));
                m_list.BeginUpdate();
                m_list.DataSource = m_items;
                m_list.EndUpdate();
                m_list.ShowScrollbar = true;
            }
            this.m_list.SelectedIndex = -1;
            m_list.SelectedIndexChanged += new EventHandler(m_list_SelectedIndexChanged);
            m_cal.TodayDate = Date;
            int dayOffset = Date.Subtract(GetBaseDate()).Days;

            for (int i = 0; i < m_arrBtnWeek.Length; i++)
            {
                Button2 btn = m_arrBtnWeek[i];
                if (i == dayOffset)
                {
                    btn.BackColor = SystemColors.Highlight;
                    btn.ForeColor = SystemColors.HighlightText;
                }
                else
                {
                    btn.BackColor = BackColor;
                    btn.ForeColor = this.ButtonForeColor(i); ;
                }
            }
            Invalidate(m_rDate);
            //m_cal.Visible = false;
        }

        private Color ButtonForeColor(int i)
        {
            Color color = this.ForeColor;
            if (i == (int)DayOfWeek.Sunday)
                color = this.m_brSundayFG.Color;
            else if (i == (int)DayOfWeek.Saturday)
                color = this.m_brSaturdayFG.Color;

            return color;
        }
        private void WeekDay_Click(object sender, EventArgs e)
        {
            int i = 0;
            while( !m_arrBtnWeek[i].Equals(sender))
                i++;
            Date = GetBaseDate().AddDays(i);
            m_list.Focus();
        }

        private DateTime GetBaseDate()
        {
            DateTime baseDate = Date;
            while (baseDate.DayOfWeek != FirstDayOfWeek)
                baseDate = baseDate.AddDays(-1);
            return baseDate;
        }

        private void MonthCal_DateChanged(object sender, DateRangeEventArgs e)
        {
            Date = e.Start;
            this.HideMonthCalendar();
        }

        private void HideMonthCalendar()
        {
            if (this.m_cal.Visible)
                this.m_cal.Visible = false;
        }

    }

}
